package com.xiaozhen.jt809.handler.server;

import com.alibaba.fastjson.JSONObject;
import com.xiaozhen.jt809.constant.JT809BusinessConstant;
import com.xiaozhen.jt809.domain.JT809MessageInfo;
import com.xiaozhen.jt809.domain.UpExgMsg;
import com.xiaozhen.jt809.handler.MyHandler;
import com.xiaozhen.jt809.utils.ByteArrayUtil;
import com.xiaozhen.jt809.utils.DateUtil;
import com.xiaozhen.jt809.utils.PacketUtil;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.function.StreamBridge;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * HISTORY
 *
 * @author zhenweisheng
 * @date 2021/9/17 10:45
 * @description:
 */
@Slf4j
@Service
public class UpExgMsgHandler implements MyHandler {

    @Autowired
    private StreamBridge streamBridge;

    @Override
    public void handler(ChannelHandlerContext ctx, JT809MessageInfo messageInfo) {
        byte[] messageBody = messageInfo.getMessageBody();
        int index = 0;
        String vehicleNo = ByteArrayUtil.bytes2gbkString(ByteArrayUtil.subBytes(messageBody, index, 21));
        vehicleNo = vehicleNo.replaceAll("\\u0000", "");
        index += 21;
        int vehicleColor = ByteArrayUtil.bytes2int(ByteArrayUtil.subBytes(messageBody, index, 1));
        index += 1;
        int dataType = ByteArrayUtil.bytes2int(ByteArrayUtil.subBytes(messageBody, index, 2));
        index += 2;
        int dataLen = ByteArrayUtil.bytes2int(ByteArrayUtil.subBytes(messageBody, index, 4));
        index += 4;
        byte[] data = ByteArrayUtil.subBytes(messageBody, index, dataLen);
        index += dataLen;
        UpExgMsg upExgMsg = new UpExgMsg();
        upExgMsg.setVehicleNo(vehicleNo);
        upExgMsg.setVehicleColor(vehicleColor);
        upExgMsg.setDataType(dataType);
        upExgMsg.setDataLen(dataLen);
        upExgMsg.setData(data);
        byte[] dataTypeBytes = ByteArrayUtil.int2bytes(dataType);
        log.info("子业务类型：" + ByteArrayUtil.bytes2HexStr(ByteArrayUtil.subBytes(dataTypeBytes, 2, 2)));
        switch (dataType) {
            case JT809BusinessConstant.UpExgMsg.UP_EXG_MSG_REGISTER:
                upExgRegisterHandler(upExgMsg);
                break;
            case JT809BusinessConstant.UpExgMsg.UP_EXG_MSG_REAL_LOCATION:
                upExgMsgRealLocationHandler(upExgMsg);
                break;
            case JT809BusinessConstant.UpExgMsg.UP_EXG_MSG_HISTORY_LOCATION:
                upExgMsgHistoryLocation(upExgMsg);
                break;
            default:
                log.info("正在紧急开发中");
        }

    }


    /**
     * 车辆注册信息处理
     *
     * @param msg
     */
    private void upExgRegisterHandler(UpExgMsg msg) {
        int index = 0;
        String platformId = ByteArrayUtil.bytes2gbkString(ByteArrayUtil.subBytes(msg.getData(), index, 11));
        index += 11;
        String producerId = ByteArrayUtil.bytes2gbkString(ByteArrayUtil.subBytes(msg.getData(), index, 11));
        index += 11;
        String terminalModelType = ByteArrayUtil.bytes2gbkString(ByteArrayUtil.subBytes(msg.getData(), index, 8));
        index += 8;
        String terminalId = ByteArrayUtil.bytes2gbkString(ByteArrayUtil.subBytes(msg.getData(), index, 7));
        index += 7;
        String terminalSimCode = ByteArrayUtil.bytes2gbkString(ByteArrayUtil.subBytes(msg.getData(), index, 12));
        index += 12;

        UpExgMsg.UpExgMsgRegister register = new UpExgMsg.UpExgMsgRegister();
        register.setPlatformId(platformId);
        register.setProducerId(producerId);
        register.setTerminalModelType(terminalModelType);
        register.setTerminalId(terminalId);
        register.setTerminalSimCode(terminalSimCode);
        msg.setUpExgMsgRegister(register);
        sendUpExgMsg(msg);
        log.info("车辆动态信息交换-车辆注册信息：" + JSONObject.toJSONString(msg));
    }

    /**
     * 车辆实时定位信息处理
     *
     * @param msg
     */
    private void upExgMsgRealLocationHandler(UpExgMsg msg) {
        int index = 0;
        int encrypy = ByteArrayUtil.bytes2int(ByteArrayUtil.subBytes(msg.getData(), index, 1));
        index += 1;
        byte[] dateTime = ByteArrayUtil.subBytes(msg.getData(), index, 7);
        index += 7;
        double lon = PacketUtil.parseLonOrLat(ByteArrayUtil.subBytes(msg.getData(), index, 4));
        index += 4;
        double lat = PacketUtil.parseLonOrLat(ByteArrayUtil.subBytes(msg.getData(), index, 4));
        index += 4;
        int vec1 = ByteArrayUtil.bytes2int(ByteArrayUtil.subBytes(msg.getData(), index, 2));
        index += 2;
        int vec2 = ByteArrayUtil.bytes2int(ByteArrayUtil.subBytes(msg.getData(), index, 2));
        index += 2;
        int vec3 = ByteArrayUtil.bytes2int(ByteArrayUtil.subBytes(msg.getData(), index, 4));
        index += 4;
        int direction = ByteArrayUtil.bytes2int(ByteArrayUtil.subBytes(msg.getData(), index, 2));
        index += 2;
        int altitude = ByteArrayUtil.bytes2int(ByteArrayUtil.subBytes(msg.getData(), index, 2));
        index += 2;
        String state = ByteArrayUtil.bytes2bitStr(ByteArrayUtil.subBytes(msg.getData(), index, 4));
        index += 4;
        String alarm = ByteArrayUtil.bytes2bitStr(ByteArrayUtil.subBytes(msg.getData(), index, 4));
        index += 4;

        UpExgMsg.UpExgMsgRealLocation location = new UpExgMsg.UpExgMsgRealLocation();
        location.setEncrypy(encrypy);
        location.setDateTime(DateUtil.parseDateTime(dateTime));
        location.setLon(lon);
        location.setLat(lat);
        location.setVec1(vec1);
        location.setVec2(vec2);
        location.setVec3(vec3);
        location.setDirection(direction);
        location.setAltitude(altitude);

        UpExgMsg.UpExgMsgRealLocation.State upExgState = new UpExgMsg.UpExgMsgRealLocation.State();
        int stateIdx = 0;
        upExgState.setStateAcc(Integer.parseInt(state.substring(stateIdx, ++stateIdx)));
        upExgState.setStateLocation(Integer.parseInt(state.substring(stateIdx, ++stateIdx)));
        upExgState.setStateLon(Integer.parseInt(state.substring(stateIdx, ++stateIdx)));
        upExgState.setStateLat(Integer.parseInt(state.substring(stateIdx, ++stateIdx)));
        upExgState.setStateOperation(Integer.parseInt(state.substring(stateIdx, ++stateIdx)));
        upExgState.setStateLatLonEncryption(Integer.parseInt(state.substring(stateIdx, ++stateIdx)));
        upExgState.setStateForwardCollisionWarning(Integer.parseInt(state.substring(stateIdx, ++stateIdx)));
        upExgState.setStateLaneDepartureWarning(Integer.parseInt(state.substring(stateIdx, ++stateIdx)));
        upExgState.setStateLoadRating(Integer.parseInt(state.substring(stateIdx, ++stateIdx)) * 2 + Integer.parseInt(state.substring(stateIdx, ++stateIdx)));
        upExgState.setStateOilPath(Integer.parseInt(state.substring(stateIdx, ++stateIdx)));
        upExgState.setStateElectricCircuit(Integer.parseInt(state.substring(stateIdx, ++stateIdx)));
        upExgState.setStateDoor(Integer.parseInt(state.substring(stateIdx, ++stateIdx)));
        location.setState(upExgState);

        UpExgMsg.UpExgMsgRealLocation.Alarm upExgAlarm = new UpExgMsg.UpExgMsgRealLocation.Alarm();
        int alarmIdx = 0;
        upExgAlarm.setAlarmEmergency(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmOverSpeed(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmFatigueDriving(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmEarlyWarning(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmGnssModuleError(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmGnssAntennaDisconnect(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmGnssAntennaShortCircuit(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmTerminalMainPowerUnderVoltage(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmTerminalMainPowerFailure(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmTerminalLcdError(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmTtsModuleError(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmCameraError(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmIcModuleError(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmOverSpeedWarning(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmDriverFatigueMonitor(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmBanOnDrivingWarning(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmCumulativeDrivingTimeout(Integer.parseInt(alarm.substring(alarmIdx += 2, ++alarmIdx)));
        upExgAlarm.setAlarmStopTimeout(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmInOutArea(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmInOutRoute(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmRoadDrivingTimeout(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmLaneDepartureError(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmVssError(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmOilError(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmStolen(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmIllegalIgnition(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmIllegalMove(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmCollisionRollover(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmRolloverWarning(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        location.setAlarm(upExgAlarm);

        msg.setUpExgMsgRealLocation(location);
        sendUpExgMsg(msg);
        log.info("车辆动态信息交换-车辆实时定位信息：" + JSONObject.toJSONString(msg));
    }


    public void upExgMsgHistoryLocation(UpExgMsg msg) {
        byte[] data = msg.getData();
        int index = 0;
        //补报的信息个数
        int gnssCnt = ByteArrayUtil.bytes2int(ByteArrayUtil.subBytes(data, index, 1));
        index += 1;

        List<UpExgMsg.UpExgMsgRealLocation> upExgMsgRealLocationList = new ArrayList<>();
        getHistoryLocationInfos(ByteArrayUtil.subBytes(data, index, data.length - index), upExgMsgRealLocationList);
        UpExgMsg.UpExgMsgHistoryLocation upExgMsgHistoryLocation = new UpExgMsg.UpExgMsgHistoryLocation();
        upExgMsgHistoryLocation.setGnssCnt(gnssCnt);
        upExgMsgHistoryLocation.setUpExgMsgRealLocationList(upExgMsgRealLocationList);
        msg.setUpExgMsgHistoryLocation(upExgMsgHistoryLocation);
        sendUpExgMsg(msg);
        log.info("车辆动态信息交换-车辆定位信息自动补报：" + JSONObject.toJSONString(msg));
    }

    /**
     * 获取补报的定位信息列表
     *
     * @param data
     * @param upExgMsgRealLocationList
     */
    public void getHistoryLocationInfos(byte[] data, List<UpExgMsg.UpExgMsgRealLocation> upExgMsgRealLocationList) {
        int index = 0;
        int encrypy = ByteArrayUtil.bytes2int(ByteArrayUtil.subBytes(data, index, 1));
        index += 1;
        byte[] dateTime = ByteArrayUtil.subBytes(data, index, 7);
        index += 7;
        double lon = PacketUtil.parseLonOrLat(ByteArrayUtil.subBytes(data, index, 4));
        index += 4;
        double lat = PacketUtil.parseLonOrLat(ByteArrayUtil.subBytes(data, index, 4));
        index += 4;
        int vec1 = ByteArrayUtil.bytes2int(ByteArrayUtil.subBytes(data, index, 2));
        index += 2;
        int vec2 = ByteArrayUtil.bytes2int(ByteArrayUtil.subBytes(data, index, 2));
        index += 2;
        int vec3 = ByteArrayUtil.bytes2int(ByteArrayUtil.subBytes(data, index, 4));
        index += 4;
        int direction = ByteArrayUtil.bytes2int(ByteArrayUtil.subBytes(data, index, 2));
        index += 2;
        int altitude = ByteArrayUtil.bytes2int(ByteArrayUtil.subBytes(data, index, 2));
        index += 2;
        String state = ByteArrayUtil.bytes2bitStr(ByteArrayUtil.subBytes(data, index, 4));
        index += 4;
        String alarm = ByteArrayUtil.bytes2bitStr(ByteArrayUtil.subBytes(data, index, 4));
        index += 4;

        UpExgMsg.UpExgMsgRealLocation location = new UpExgMsg.UpExgMsgRealLocation();
        location.setEncrypy(encrypy);
        location.setDateTime(DateUtil.parseDateTime(dateTime));
        location.setLon(lon);
        location.setLat(lat);
        location.setVec1(vec1);
        location.setVec2(vec2);
        location.setVec3(vec3);
        location.setDirection(direction);
        location.setAltitude(altitude);

        UpExgMsg.UpExgMsgRealLocation.State upExgState = new UpExgMsg.UpExgMsgRealLocation.State();
        int stateIdx = 0;
        upExgState.setStateAcc(Integer.parseInt(state.substring(stateIdx, ++stateIdx)));
        upExgState.setStateLocation(Integer.parseInt(state.substring(stateIdx, ++stateIdx)));
        upExgState.setStateLon(Integer.parseInt(state.substring(stateIdx, ++stateIdx)));
        upExgState.setStateLat(Integer.parseInt(state.substring(stateIdx, ++stateIdx)));
        upExgState.setStateOperation(Integer.parseInt(state.substring(stateIdx, ++stateIdx)));
        upExgState.setStateLatLonEncryption(Integer.parseInt(state.substring(stateIdx, ++stateIdx)));
        upExgState.setStateForwardCollisionWarning(Integer.parseInt(state.substring(stateIdx, ++stateIdx)));
        upExgState.setStateLaneDepartureWarning(Integer.parseInt(state.substring(stateIdx, ++stateIdx)));
        upExgState.setStateLoadRating(Integer.parseInt(state.substring(stateIdx, ++stateIdx)) * 2 + Integer.parseInt(state.substring(stateIdx, ++stateIdx)));
        upExgState.setStateOilPath(Integer.parseInt(state.substring(stateIdx, ++stateIdx)));
        upExgState.setStateElectricCircuit(Integer.parseInt(state.substring(stateIdx, ++stateIdx)));
        upExgState.setStateDoor(Integer.parseInt(state.substring(stateIdx, ++stateIdx)));
        location.setState(upExgState);

        UpExgMsg.UpExgMsgRealLocation.Alarm upExgAlarm = new UpExgMsg.UpExgMsgRealLocation.Alarm();
        int alarmIdx = 0;
        upExgAlarm.setAlarmEmergency(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmOverSpeed(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmFatigueDriving(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmEarlyWarning(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmGnssModuleError(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmGnssAntennaDisconnect(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmGnssAntennaShortCircuit(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmTerminalMainPowerUnderVoltage(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmTerminalMainPowerFailure(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmTerminalLcdError(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmTtsModuleError(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmCameraError(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmIcModuleError(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmOverSpeedWarning(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmDriverFatigueMonitor(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmBanOnDrivingWarning(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmCumulativeDrivingTimeout(Integer.parseInt(alarm.substring(alarmIdx += 2, ++alarmIdx)));
        upExgAlarm.setAlarmStopTimeout(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmInOutArea(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmInOutRoute(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmRoadDrivingTimeout(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmLaneDepartureError(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmVssError(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmOilError(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmStolen(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmIllegalIgnition(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmIllegalMove(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmCollisionRollover(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        upExgAlarm.setAlarmRolloverWarning(Integer.parseInt(alarm.substring(alarmIdx, ++alarmIdx)));
        location.setAlarm(upExgAlarm);
        upExgMsgRealLocationList.add(location);
        //如果剩余长度大于等于一条数据就继续获取
        if (data.length > index && data.length - index >= index) {
            getHistoryLocationInfos(ByteArrayUtil.subBytes(data, index, data.length - index), upExgMsgRealLocationList);
        }
    }

    @Async
    public void sendUpExgMsg(UpExgMsg upExgMsg){
        streamBridge.send("upExg-out-0",upExgMsg);
    }
}
